/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server;

import SBLib.File;
import SBLib.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Handles the replication requests by the other RMs
 * @author BrandonNeal
 */
public class ReplicatorWorker extends Thread {

    private Socket rmSocket;
    final private ArrayList<File> Files;
    final private ArrayList<User> Users;
    
    private ObjectInputStream in;
    private ObjectOutputStream out;
        
    String Message;
    String[] chunks;
    
    
    public ReplicatorWorker(Socket rmSocket, ArrayList<File> Files, ArrayList<User> Users) 
    {
       this.Files = Files;
       this.Users = Users;
       
       try
       {
            this.rmSocket = rmSocket;
            this.in = new ObjectInputStream(this.rmSocket.getInputStream());
            this.out = new ObjectOutputStream(this.rmSocket.getOutputStream());

            this.start(); //Start Worker Thread
        
        }
       catch (IOException ex) 
       {
            Logger.getLogger(ServerWorker.class.getName()).log(Level.SEVERE, null, ex);
       }
    }
    
    /**
     * - Gets request from another replication server.
     * - passes it to HandleRequest to deal with it.
     */
    @Override
    public void run()
    {
        
        try
        {
           String fromReplication = (String) this.in.readObject();
           System.out.println("Recieved:" + fromReplication);
           this.HandleRequest(fromReplication);
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(ServerWorker.class.getName()).log(Level.SEVERE, null, ex);
        } 
        catch (ClassNotFoundException ex) 
        {
            Logger.getLogger(ServerWorker.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**
     * Taken from RequestHandler.java class. Gets the type of request, then uses reflection to call the appropriate handler function.
     * @param request 
     */
    public void HandleRequest(String request) 
    {
        this.chunks=request.split(Server.SPLIT); //split the request string to get the meaningful data
        String type = this.getChunk(0); //get request type
        
        try {
            try {
                
                this.getClass().getMethod(type.toLowerCase()).invoke(this); //Use reflection to call the function that the request is for
           
            } 
            catch (IllegalAccessException ex) {
                Logger.getLogger(RequestHandler.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(RequestHandler.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(RequestHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
                    
        } 
        //Comes here if the method was not found
        catch (NoSuchMethodException ex) {
            
                 
            Logger.getLogger(RequestHandler.class.getName()).log(Level.SEVERE, null, ex);
            
        } catch (SecurityException ex) {
            Logger.getLogger(RequestHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
    }
    /**
     * Replicates the creation of a new User
     */
    public void new_user()
    {
        String username = this.getChunk(1);
        String password = this.getChunk(2);
        User user = new User(username,password);
        this.Users.add(user);
        user.SaveUser();
    }
    /**
     * Replicates the creation of a new File
     */
    public void new_file()
    {
        String filename = this.getChunk(1);
        String content = this.getChunk(2);
        
        File file = new File(filename, content);
        file.SaveFile();
        this.Files.add(file);
    }
    /**
     * Replicates the editing of an existing File's content
     */
    public void edit_file()
    {
        String filename = this.getChunk(1);
        String newContent = this.getChunk(2);
        
        File file = new File(filename, newContent);
        int index = this.Files.indexOf(file);
        File oldFile = this.Files.get(index);
        
        oldFile.EditFile(newContent);
    }
    /**
     * Replicates the renaming of an existing File
     */
    public void rename_file()
    {
        String filename = this.getChunk(1);
        String newFilename = this.getChunk(2);
        File file = new File(filename,"");
        this.Files.get(this.Files.indexOf(file)).RenameFile(newFilename);
        
    }
    /**
     * Replicates the deletion of a file
     */
    public void delete_file()
    {
        String filename = this.getChunk(1);
        File file = new File(filename, "");
                
        file.DeleteFile();
        this.Files.remove(file);
        
    }
    public void lock_file()
    {
        String filename = this.getChunk(1);
        String username = this.getChunk(2);
        File tempFile = new File(filename, "");
        this.Files.get(this.Files.indexOf(tempFile)).Lock(username);
        
    }
    public void unlock_file()
    {
        String filename = this.getChunk(1);
        String username = this.getChunk(2);
        File tempFile = new File(filename, "");
        this.Files.get(this.Files.indexOf(tempFile)).Unlock(username);
        
    }
    private String getChunk(int i)
    {
        return this.chunks[i];
    }
    
}
